/* 
Copyright (C) 2006-2010 Ricardo Pescuma Domenecci

This is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this file; see the file license.txt.  If
not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  
*/


#include "commons.h"


static LRESULT CALLBACK EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK AddReplacementDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);


struct Data
{
	Dictionary *dict;
	tstring find;
	tstring replace;
	BOOL useVariables;

	BOOL modal;
	BOOL findReadOnly;

	AutoReplaceDialogCallback callback;
	void *param;
	
	WNDPROC old_edit_proc;
};

BOOL ShowAutoReplaceDialog(HWND parent, BOOL modal, 
						   Dictionary *dict, const TCHAR *find, const TCHAR *replace, BOOL useVariables,
						   BOOL findReadOnly, AutoReplaceDialogCallback callback, void *param)
{
	Data *data = new Data();
	data->dict = dict;
	data->useVariables = useVariables;
	data->modal = modal;
	data->findReadOnly = findReadOnly;
	data->callback = callback;
	data->param = param;

	if (find != NULL)
		data->find = find;

	if (replace != NULL)
		data->replace = replace;

	if (modal)
	{
		return DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ADD_REPLACEMENT), parent, 
							  AddReplacementDlgProc, (LPARAM) data);
	}
	else
	{
		HWND hwnd = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ADD_REPLACEMENT), parent, 
									  AddReplacementDlgProc, (LPARAM) data);
		SetForegroundWindow(hwnd);
		SetFocus(hwnd);
		SetFocus(GetDlgItem(hwnd, IDC_NEW));
		ShowWindow(hwnd, SW_SHOW);
		return TRUE;
	}
}


static LRESULT CALLBACK OnlyCharsEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	Data *data = (Data *) GetWindowLongPtr(hwnd, GWLP_USERDATA);

	switch(msg)
	{
		case WM_CHAR:
		{
			if (wParam == VK_BACK)
				break;
			if (lParam & (1 << 28))	// ALT key
				break;
			if (GetKeyState(VK_CONTROL) & 0x8000)	// CTRL key
				break;

			TCHAR c = (TCHAR) wParam;
			if (!data->dict->autoReplace->isWordChar(c))
				return 1;

			TCHAR tmp[2] = { c, 0 };
			CharLower(tmp);
			wParam = tmp[0];

			break;
		}
	}

	LRESULT ret = CallWindowProc(data->old_edit_proc, hwnd, msg, wParam, lParam);

	switch(msg)
	{
		case EM_PASTESPECIAL:
		case WM_PASTE:
		{
			TCHAR text[256];
			GetWindowText(hwnd, text, MAX_REGS(text));

			scoped_free<TCHAR> dest = data->dict->autoReplace->filterText(text);
			SetWindowText(hwnd, dest);
			break;
		}
	}

	return ret;

}


static BOOL CenterParent(HWND hwnd)
{
	HWND hwndParent = GetParent(hwnd);
	if (hwndParent == NULL)
		return FALSE;

	RECT rect, rectP;
	GetWindowRect(hwnd, &rect);
	GetWindowRect(hwndParent, &rectP);

	int width  = rect.right  - rect.left;
	int height = rect.bottom - rect.top;

	int x = ((rectP.right-rectP.left) - width) / 2 + rectP.left;
	int y = ((rectP.bottom-rectP.top) - height) / 2 + rectP.top;

	int screenwidth  = GetSystemMetrics(SM_CXSCREEN);
	int screenheight = GetSystemMetrics(SM_CYSCREEN);

	if(x + width  > screenwidth)  x = screenwidth  - width;
	if(y + height > screenheight) y = screenheight - height;
	if(x < 0) x = 0;
	if(y < 0) y = 0;

	MoveWindow(hwnd, x, y, width, height, FALSE);

	return TRUE;
}

static void Close(HWND hwndDlg, int ret)
{
	Data *data = (Data *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);

	if (!ret)
	{
		data->callback(TRUE, data->dict, 
					   data->find.c_str(), data->replace.c_str(), data->useVariables, 
					   data->find.c_str(), data->param);
	}

	SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_OLD), GWLP_WNDPROC, (LONG_PTR) data->old_edit_proc);
	data->old_edit_proc = NULL;

	if (data->modal)
		EndDialog(hwndDlg, ret);
	else
		DestroyWindow(hwndDlg);

	delete data;
}

static INT_PTR CALLBACK AddReplacementDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
		case WM_INITDIALOG:
		{
			TranslateDialogDefault(hwndDlg);

			Data *data = (Data *) lParam;
			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) data);

			SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_OLD), GWLP_USERDATA, (LONG_PTR) data);
			data->old_edit_proc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_OLD), GWLP_WNDPROC, 
														  (LONG_PTR) OnlyCharsEditProc);

			HICON hIcon = IcoLib_LoadIcon("spellchecker_enabled");
			SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
			IcoLib_ReleaseIcon(hIcon);

			SendDlgItemMessage(hwndDlg, IDC_OLD, EM_LIMITTEXT, 256, 0);
			SendDlgItemMessage(hwndDlg, IDC_NEW, EM_LIMITTEXT, 256, 0);

			if (!data->find.empty())
			{
				scoped_free<TCHAR> tmp = data->dict->autoReplace->filterText(data->find.c_str());
				SetDlgItemText(hwndDlg, IDC_OLD, tmp);
			}
			if (!data->replace.empty())
				SetDlgItemText(hwndDlg, IDC_NEW, data->replace.c_str());

			CheckDlgButton(hwndDlg, IDC_VARIABLES, data->useVariables ? BST_CHECKED : BST_UNCHECKED);

			if (data->findReadOnly)
			{
				SendDlgItemMessage(hwndDlg, IDC_OLD, EM_SETREADONLY, TRUE, 0);
				EnableWindow(GetDlgItem(hwndDlg, IDC_OLD_PS), FALSE);
			}

			if (!variables_enabled)
			{
				ShowWindow(GetDlgItem(hwndDlg, IDC_VARIABLES), FALSE);
				ShowWindow(GetDlgItem(hwndDlg, IDC_VAR_HELP), FALSE);

				RECT rc_old;
				GetWindowRect(GetDlgItem(hwndDlg, IDC_OLD), &rc_old);
				RECT rc_new;
				GetWindowRect(GetDlgItem(hwndDlg, IDC_NEW), &rc_new);
				rc_new.right = rc_old.right;

				SetWindowPos(GetDlgItem(hwndDlg, IDC_NEW), NULL, 0, 0, 
						   rc_new.right - rc_new.left, rc_new.bottom - rc_new.top, 
						   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOZORDER);
			}
			else
			{
				variables_skin_helpbutton(hwndDlg, IDC_VAR_HELP);
				EnableWindow(GetDlgItem(hwndDlg, IDC_VAR_HELP), IsDlgButtonChecked(hwndDlg, IDC_VARIABLES));
			}

			CenterParent(hwndDlg);

			return TRUE;
		}

		case WM_COMMAND:
			switch(wParam)
			{
				case IDOK:
				{
					Data *data = (Data *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);

					TCHAR find[256];
					if (data->findReadOnly)
					{
						lstrcpyn(find, data->find.c_str(), MAX_REGS(find));
					}
					else
					{
						GetDlgItemText(hwndDlg, IDC_OLD, find, MAX_REGS(find));
						lstrtrim(find);
					}

					TCHAR replace[256];
					GetDlgItemText(hwndDlg, IDC_NEW, replace, MAX_REGS(replace));
					lstrtrim(replace);

					if (!data->findReadOnly && find[0] == 0)
					{
						MessageBox(hwndDlg, TranslateT("The wrong word can't be empty!"), TranslateT("Wrong Correction"), 
							MB_OK | MB_ICONERROR);
					}
					else if (replace[0] == 0)
					{
						MessageBox(hwndDlg, TranslateT("The correction can't be empty!"), TranslateT("Wrong Correction"), 
							MB_OK | MB_ICONERROR);
					}
					else if (_tcscmp(find, replace) == 0)
					{
						MessageBox(hwndDlg, TranslateT("The correction can't be equal to the wrong word!"), TranslateT("Wrong Correction"), 
							MB_OK | MB_ICONERROR);
					}
					else
					{
						data->callback(FALSE, data->dict, 
									   find, replace, IsDlgButtonChecked(hwndDlg, IDC_VARIABLES), 
									   data->find.c_str(), data->param);
						Close(hwndDlg, 1);
					}

					break;
				}
				case IDCANCEL:
				{
					Close(hwndDlg, 0);
					break;
				}
				case IDC_VARIABLES:
				{					
					EnableWindow(GetDlgItem(hwndDlg, IDC_VAR_HELP), IsDlgButtonChecked(hwndDlg, IDC_VARIABLES));
					break;
				}
				case IDC_VAR_HELP:
				{
					variables_showhelp(hwndDlg, IDC_NEW, VHF_FULLDLG, NULL, "The wrong word typed by the user");
					break;
				}
			}
			break;

		case WM_CLOSE:
		{
			Close(hwndDlg, 0);
			break;
		}
	}
	
	return FALSE;
}
